package JoReg

const (
	MAX_DFA_STATE_COUNT = 255
	STATE_FAIL          = -1
)

type DfaManager struct {
	nfaManagerPtr      *NfaManager
	stateIndex         int
	dfaSlc             []*Dfa
	dfaStateTransTable [MAX_DFA_STATE_COUNT][ASCII_COUNT]int
}

func MakeDfaManager(nfaManagerPtr *NfaManager) *DfaManager {
	dfaManagerPtr := &DfaManager{
		nfaManagerPtr: nfaManagerPtr,
		stateIndex:    0,
		dfaSlc:        make([]*Dfa, 0),
	}
	return dfaManagerPtr
}

// NfaToDfa NFA转DFA
func (this *DfaManager) NfaToDfa() {
	accessibleSet := make(map[*Nfa]struct{})
	eClosureSet := make(map[*Nfa]struct{})
	accessibleSet[this.nfaManagerPtr.startNfaPtr] = struct{}{}
	eClosureSet = this.eClosure(accessibleSet)
	dfaPtr := MakeDfa(this, eClosureSet)
	this.dfaSlc = append(this.dfaSlc, dfaPtr)
	dfaIndex := 0
	pointDfaState := STATE_FAIL
	for {
		if dfaIndex >= len(this.dfaSlc) {
			break
		}
		for i := byte(0); i < ASCII_COUNT; i++ {
			accessibleSet = this.move(this.dfaSlc[dfaIndex].nfaSet, i)
			if len(accessibleSet) > 0 {
				// 有可达的状态
				eClosureSet = this.eClosure(accessibleSet)
				existDfaPtr := this.hasDfaState(eClosureSet)
				if existDfaPtr == nil {
					// 当前的ε闭包在dfaSlc中不存在 -- 创建新的dfa状态
					dfaPtr = MakeDfa(this, eClosureSet)
					this.dfaSlc = append(this.dfaSlc, dfaPtr)
					pointDfaState = dfaPtr.stateIndex
				} else {
					// 已经存在相同的nfaSet集合, 使用已存在的dfa状态值
					pointDfaState = existDfaPtr.stateIndex
				}
			} else {
				// 不可达
				pointDfaState = STATE_FAIL
			}
			this.dfaStateTransTable[this.dfaSlc[dfaIndex].stateIndex][i] = pointDfaState
		}
		dfaIndex++
	}
}

func (this *DfaManager) match(str string) []string {
	charSlc := []byte(str)
	curDfaStateNumber := 0
	acceptFlag := false
	matchSlc := make([]string, 0)
	validStr := ""
	for i, char := range charSlc {
		curDfaStateNumber = this.dfaStateTransTable[curDfaStateNumber][char]
		if curDfaStateNumber > 0 && this.dfaSlc[curDfaStateNumber].acceptFlag {
			acceptFlag = true
		}
		if curDfaStateNumber == STATE_FAIL {
			// 不可达但有可接受状态
			if acceptFlag {
				matchSlc = append(matchSlc, validStr)
			}
			validStr = ""
			curDfaStateNumber = 0
			acceptFlag = false
		} else {
			validStr += string(char)
			if i+1 >= len(charSlc) && acceptFlag {
				matchSlc = append(matchSlc, validStr)
			}
		}
	}
	return matchSlc
}

// eClosure 计算可达状态的空边集合
func (this *DfaManager) eClosure(nfaStateSet map[*Nfa]struct{}) map[*Nfa]struct{} {
	eClosureSet := this.nfaManagerPtr.eClosure(nfaStateSet)
	for nfaPtr, _ := range nfaStateSet {
		eClosureSet[nfaPtr] = struct{}{}
	}
	return eClosureSet
}

// move 匹配可达状态集合
func (this *DfaManager) move(eClosureSet map[*Nfa]struct{}, char byte) map[*Nfa]struct{} {
	return this.nfaManagerPtr.move(eClosureSet, char)
}

// 判断是否已存在相同的nfa集合
func (this *DfaManager) hasDfaState(nfaSet map[*Nfa]struct{}) *Dfa {
	for _, dfaPtr := range this.dfaSlc {
		if len(dfaPtr.nfaSet) == len(nfaSet) {
			equalFlag := true
			for dfaNfaPtr := range dfaPtr.nfaSet {
				if _, ok := nfaSet[dfaNfaPtr]; !ok {
					equalFlag = false
					break
				}
			}
			if equalFlag {
				return dfaPtr
			}
		}
	}
	return nil
}
